package cn.dzhang.spring.boot.remoting;

import java.io.IOException;
import java.net.HttpURLConnection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor;

public class BasicAuthenticationHttpInvokerRequestExecutor extends
		SimpleHttpInvokerRequestExecutor {

	private static final Log log = LogFactory
			.getLog(BasicAuthenticationHttpInvokerRequestExecutor.class);

	/**
	 * Provided so subclasses can perform additional configuration if required
	 * (eg set additional request headers for non-security related information
	 * etc).
	 *
	 * @param con
	 *            the HTTP connection to prepare
	 * @param contentLength
	 *            the length of the content to send
	 *
	 * @throws IOException
	 *             if thrown by HttpURLConnection methods
	 */
	protected void doPrepareConnection(HttpURLConnection con, int contentLength)
			throws IOException {
	}

	/**
	 * Called every time a HTTP invocation is made.
	 * <p>
	 * Simply allows the parent to setup the connection, and then adds an
	 * <code>Authorization</code> HTTP header property that will be used for
	 * BASIC authentication.
	 * </p>
	 * <p>
	 * The <code>SecurityContextHolder</code> is used to obtain the relevant
	 * principal and credentials.
	 * </p>
	 *
	 * @param con
	 *            the HTTP connection to prepare
	 * @param contentLength
	 *            the length of the content to send
	 *
	 * @throws IOException
	 *             if thrown by HttpURLConnection methods
	 */
	protected void prepareConnection(HttpURLConnection con, int contentLength)
			throws IOException {
		super.prepareConnection(con, contentLength);

		Authentication auth = AuthenticationContextHolder
				.currentAuthentication();

		if ((auth != null) && (auth.getUsername() != null)
				&& (auth.getPassword() != null)) {
			String base64 = auth.getUsername() + ":" + auth.getPassword();
			con.setRequestProperty("Authorization", "Basic "
					+ new String(Base64.encodeBase64(base64.getBytes())));

			if (log.isDebugEnabled()) {
				log.debug("HttpInvocation now presenting via BASIC authentication SecurityContextHolder-derived: "
						+ auth.toString());
			}
		} else {
			if (log.isDebugEnabled()) {
				log.debug("Unable to set BASIC authentication header as SecurityContext did not provide "
						+ "valid Authentication: " + auth);
			}
		}

		doPrepareConnection(con, contentLength);
	}
}
